package org.hilo.boot.core.value;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.Id;

import org.hilo.boot.core.UT;

/**
 * parse the AutoValue annotation
 * 
 * @author zollty
 * @since 2018-03-20
 */
public class AutoValueInit implements FieldInitValue {
    /**
     * the third-part AutoValue Parser
     */
    private List<AutoValueParser> parsers = new LinkedList<AutoValueParser>();
    
    /**
     * Add the given object with highest precedence.
     */
    public void addFirst(AutoValueParser fieldInit) {
        this.parsers.add(0, fieldInit);
    }

    /**
     * Add the given object with lowest precedence.
     */
    public void addLast(AutoValueParser fieldInit) {
        this.parsers.add(fieldInit);
    }
    
    public void reset() {
        parsers.clear();
    }

    @Override
    public boolean initField(Field field, Object standardBean, int type) {
        AutoValue av = field.getAnnotation(AutoValue.class);
        int avType;
        if (av != null && (type==(avType = av.action()) || avType==ActionType.ANY)) {
            int strategy = av.strategy();
            
            if (strategy == StrategyType.WHEN_NULL) {
                UT.Ref.makeAccessible(field);
                if (UT.Ref.getField(field, standardBean) != null) {
                    return false;
                }
                return doInit(field, standardBean, av);
            }
            if (strategy == StrategyType.ALWAYS) {
                UT.Ref.makeAccessible(field);
                return doInit(field, standardBean, av);
            }
            if (strategy == StrategyType.CANT_BE_NULL) {
                UT.Ref.makeAccessible(field);
                if (UT.Ref.getField(field, standardBean) != null) {
                    return false;
                }
                throw new IllegalStateException(field.getName() + " field cannot be null when update");
            }
            
        }
        return false;
    }
    
    protected boolean doInit(Field field, Object standardBean, AutoValue av) {
        for (AutoValueParser parser : parsers) {
            if (parser.support(av.parser(), field)) {
                UT.Ref.setField(field, standardBean, parser.parse(av.value(), field));
                return true;
            }
        }

        if (av.parser() == Object.class) {
            return initObjectField(field, standardBean, av.value());
        } else if (av.parser() == Id.class) {
            return GerneratorIdInit.initIdField(field, standardBean);
        }
        return false;
    }
    
    
    public static boolean initObjectField(Field field, Object standardBean, String defaultVal) {
        boolean ret = true;
        Class<?> type = field.getType();
        if (type.equals(String.class)) {
            UT.Ref.setField(field, standardBean, defaultVal);
        }
        else if (type.equals(Long.class)) {
            Long val;
            if (defaultVal.length() == 0) {
                val = 0L;
            } else {
                val = Long.valueOf(defaultVal);
            }
            UT.Ref.setField(field, standardBean, val);
        }
        else if (type.equals(Integer.class)) {
            Integer val;
            if (defaultVal.length() == 0) {
                val = 0;
            } else {
                val = Integer.valueOf(defaultVal);
            }
            UT.Ref.setField(field, standardBean, val);
        }
        else if (type.equals(Byte.class)) {
            Byte val;
            if (defaultVal.length() == 0) {
                val = (byte) 0;
            } else {
                val = Byte.valueOf(defaultVal);
            }
            UT.Ref.setField(field, standardBean, val);
        }
        else if (type.equals(Boolean.class)) {
            Boolean val;
            if (defaultVal.length() == 0) {
                val = false;
            } else {
                val = Boolean.valueOf(defaultVal);
            }
            UT.Ref.setField(field, standardBean, val);
        }
        else if (type.equals(Date.class)) {
            Date val;
            if (defaultVal.length() == 0) {
                val = new Date();
            } else {
                val = new Date(Long.valueOf(defaultVal));
            }
            UT.Ref.setField(field, standardBean, val);
        }
        else if (type.equals(BigDecimal.class)) {
            BigDecimal val;
            if (defaultVal.length() == 0) {
                val = new BigDecimal(0);
            } else {
                val = new BigDecimal(defaultVal);
            }
            UT.Ref.setField(field, standardBean, val);
        }
        else if (type.equals(Float.class)) {
            Float val;
            if (defaultVal.length() == 0) {
                val = new Float(0.0);
            } else {
                val = Float.valueOf(defaultVal);
            }
            UT.Ref.setField(field, standardBean, val);
        }
        else if (type.equals(Double.class)) {
            Double val;
            if (defaultVal.length() == 0) {
                val = new Double(0.0);
            } else {
                val = Double.valueOf(defaultVal);
            }
            UT.Ref.setField(field, standardBean, val);
        }
        else if (type.equals(Short.class)) {
            Short val;
            if (defaultVal.length() == 0) {
                val = (short) 0;
            } else {
                val = Short.valueOf(defaultVal);
            }
            UT.Ref.setField(field, standardBean, val);
        } else {
            ret = false;
        }
        return ret;
    }

}
